<?php
/**
 * @since   2022-02-15
 * @author  zhaoxiang <zhaoxiang051405@gmail.com>
 */

namespace App\Controller\Admin;

use App\Constants\ErrorCode;
use App\Constants\RedisKey;
use App\Constants\ServerList;
use App\Middleware\AdminMiddleware;
use App\Model\AdminAuthGroupAccess;
use App\Model\AdminAuthRule;
use App\Model\AdminMenu;
use App\Model\AdminUser;
use App\Model\AdminUserData;
use App\Model\QmGameVersion;
use App\Service\RouterToolService;
use App\Service\ToolService;
use Hyperf\Config\Annotation\Value;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Annotation\PostMapping;
use Hyperf\Redis\Redis;
use Hyperf\Utils\ApplicationContext;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

#[Controller(prefix: '/admin/Login'), Middleware(AdminMiddleware::class)]
class LoginController extends BaseController {
    #[Value('apiadmin.online_time')]
    private int $online_time;

    /**
     * 用户登录
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    #[PostMapping(path: 'index')]
    public function index(): array {
        $username = $this->request->input('username', '');
        $password = $this->request->input('password', '');
        $serverCode = $this->request->input('server_code', '');
        if (!$username) {
            return $this->buildFailed(ErrorCode::LOGIN_ERROR, '缺少用户名!');
        }
        if (!$password) {
            return $this->buildFailed(ErrorCode::LOGIN_ERROR, '缺少密码!');
        }

        $password = ToolService::userMd5($password);
        $userInfo = AdminUser::query()->where('username', $username)->where('password', $password)->first();
        if (!empty($userInfo)) {
            if ($userInfo->getAttribute('status')) {
                //更新用户数据
                $userData = $userInfo->userData;
                if ($userData) {
                    $userData->login_times++;
                    $userData->last_login_ip = sprintf("%u", ip2long($this->getIp()));
                    $userData->last_login_time = time();
                } else {
                    $userData = new AdminUserData();
                    $userData->login_times = 1;
                    $userData->uid = $userInfo['id'];
                    $userData->last_login_ip = sprintf("%u", ip2long($this->getIp()));
                    $userData->last_login_time = time();
                    $userData->head_img = '';
                }
                $userData->save();

                $userInfo = $userInfo->toArray();
                $userInfo['access'] = $this->getAccess($userInfo['id']);
                $userInfo['menu'] = $this->getAccessMenuData($userInfo['id']);
                $apiAuth = md5(uniqid('', true) . time());

                $gv = QmGameVersion::query()->where('kong_code', $serverCode)->first();
                if ($gv) {
                    $userInfo['connection_code'] = $gv['connection_code'];
                }

                if (!empty(ServerList::ADMIN_BIND_GAMES[$serverCode])) {
                    $gamesList = explode(',', $userInfo['user_data']['bind_games']);
                    $new = [];
                    foreach ($gamesList as $value) {
                        if (in_array($value, ServerList::ADMIN_BIND_GAMES[$serverCode])) {
                            $new[] = $value;
                        }
                    }
                    $userInfo['user_data']['bind_games'] = implode(',', $new);
                }
                $userInfo['server_code'] = $serverCode;

                $redis = (ApplicationContext::getContainer())->get(Redis::class);
                $redis->set(RedisKey::ADMIN_LOGIN_AUTH . ':' . $apiAuth, json_encode($userInfo), $this->online_time);
                $redis->set(RedisKey::ADMIN_LOGIN_ID . ':' . $userInfo['id'], $apiAuth, $this->online_time);
                $userInfo['apiAuth'] = $apiAuth;

                return $this->buildSuccess($userInfo, '登录成功');
            }

            return $this->buildFailed(ErrorCode::LOGIN_ERROR, '用户已被封禁，请联系管理员');
        }

        return $this->buildFailed(ErrorCode::LOGIN_ERROR, '用户名密码不正确');
    }

    /**
     * 获取当前用户的允许菜单
     * @param int $uid
     * @return array
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    public function getAccessMenuData(int $uid): array {
        $returnData = [];
        $isSupper = ToolService::isAdministrator($uid);
        if ($isSupper) {
            $access = AdminMenu::query()->where('router', '<>', '')->get();
            $returnData = ToolService::listToTree(ToolService::buildArrFromObj($access));
        } else {
            $groups = AdminAuthGroupAccess::query()->where('uid', $uid)->first();
            if (!empty($groups) && $groups->getAttribute('group_id')) {
                $access = AdminAuthRule::query()->whereIn('group_id', explode(',', $groups->getAttribute('group_id')))->get();
                $access = array_unique(array_column(ToolService::buildArrFromObj($access), 'url'));
                $access[] = "";
                $menus = AdminMenu::query()->whereIn('url', $access)->where('show', 1)->get();
                $returnData = ToolService::listToTree(ToolService::buildArrFromObj($menus));
                RouterToolService::buildVueRouter($returnData);
            }
        }

        return array_values($returnData);
    }

    /**
     * 获取用户权限数据
     * @param int $uid
     * @return array
     */
    public function getAccess(int $uid): array {
        $isSupper = ToolService::isAdministrator($uid);
        if ($isSupper) {
            $access = AdminMenu::all();
            $access = ToolService::buildArrFromObj($access);

            return array_values(array_filter(array_column($access, 'url')));
        }

        $groups = AdminAuthGroupAccess::query()->where('uid', $uid)->first();
        if (!empty($groups) && $groups->getAttribute('group_id')) {
            $access = AdminAuthRule::query()->whereIn('group_id', explode(',', $groups->getAttribute('group_id')))->get();
            $access = ToolService::buildArrFromObj($access);

            return array_values(array_unique(array_column($access, 'url')));
        }

        return [];
    }

    /**
     * 获取用户信息
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    #[GetMapping(path: 'getUserInfo')]
    public function getUserInfo(): array {
        $userDataArr = $this->uInfo();

        return $this->buildSuccess($userDataArr);
    }

    /**
     * 用户登出
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    #[GetMapping(path: 'logout')]
    public function logout(): array {
        $userDataArr = $this->uInfo();
        $redis = (ApplicationContext::getContainer())->get(Redis::class);
        $apiAuth = $redis->get(RedisKey::ADMIN_LOGIN_ID . ':' . $userDataArr['id']);
        if ($apiAuth) {
            $redis->del(RedisKey::ADMIN_LOGIN_AUTH . ':' . $apiAuth);
            $redis->del(RedisKey::ADMIN_LOGIN_ID . ':' . $userDataArr['id']);
        }

        return $this->buildSuccess([], '登出成功');
    }

    /**
     * 获取当前用户的允许菜单
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    #[GetMapping(path: 'getAccessMenu')]
    public function getAccessMenu(): array {
        $userDataArr = $this->uInfo();

        return $this->buildSuccess($this->getAccessMenuData($userDataArr['id']));
    }
}
